<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../src/polymer-lib.html">
  <link rel="import" href="../../src/lib/async.html">
</head>
<body>

<script>
/* global Async */
  setup(function() {
    window.Async = Polymer.Async;
  });

  teardown(function() {
    delete window.Async;
  });

  suite('no-wait async', function() {

    test('async runs', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      Async.run(callback);
      setTimeout(function() {
        assert.equal(called, 1);
        done();
      });
    });

    test('multiple asyncs of same fn run', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      Async.run(callback);
      Async.run(callback);
      Async.run(callback);
      setTimeout(function() {
        assert.equal(called, 3);
        done();
      });
    });

    test('multiple asyncs of different fns run', function(done) {
      var called1 = 0;
      var called2 = 0;
      var called3 = 0;
      var callback1 = function() {
        called1++;
      };
      var callback2 = function() {
        called2++;
      };
      var callback3 = function() {
        called3++;
      };
      Async.run(callback1);
      Async.run(callback2);
      Async.run(callback3);
      setTimeout(function() {
        assert.equal(called1, 1);
        assert.equal(called2, 1);
        assert.equal(called3, 1);
        done();
      });
    });

    test('error handling', function(done) {
      var called1 = 0;
      var called2 = 0;
      var called3 = 0;
      var called4 = 0;
      var called5 = 0;
      var callback1 = function() {
        called1++;
      };
      var callback2 = function() {
        called2++;
        throw new Error('intentional error 1');
      };
      var callback3 = function() {
        called3++;
        Async.run(callback5);
        throw new Error('intentional error 2');
      };
      var callback4 = function() {
        called4++;
      };
      var callback5 = function() {
        called5++;
      };
      Async.run(callback1);
      Async.run(callback2);
      Async.run(callback3);
      Async.run(callback4);
      // Force synchronous microtask, since we can't catch the error otherwise
      assert.throws(function() {
        Async._atEndOfMicrotask();
      });
      // Have been called
      assert.equal(called1, 1);
      assert.equal(called2, 1);
      // Not yet called, due to exception
      assert.equal(called3, 0);
      assert.equal(called4, 0);
      assert.equal(called5, 0);
      // Force next synchronous microtask
      assert.throws(function() {
        Async._atEndOfMicrotask();
      });
      // Have been called
      assert.equal(called1, 1);
      assert.equal(called2, 1);
      assert.equal(called3, 1);
      // Not yet called, due to exception
      assert.equal(called4, 0);
      assert.equal(called5, 0);
      // Wait for actual microtask, and verify remaining queue was flushed
      setTimeout(function() {
        // Have been called
        assert.equal(called1, 1);
        assert.equal(called2, 1);
        assert.equal(called3, 1);
        assert.equal(called4, 1);
        assert.equal(called5, 1);
        done();
      });
    });

  });

  suite('cancel no-wait async', function() {

    test('async cancels', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      var h = Async.run(callback);
      Async.cancel(h);
      setTimeout(function() {
        assert.equal(called, 0);
        done();
      });
    });

    test('multiple asyncs of same fn cancel', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      var h = [];
      h.push(Async.run(callback));
      h.push(Async.run(callback));
      h.push(Async.run(callback));
      Async.cancel(h.pop());
      Async.cancel(h.pop());
      Async.cancel(h.pop());
      setTimeout(function() {
        assert.equal(called, 0);
        done();
      });
    });

    test('multiple asyncs of different fns cancel', function(done) {
      var called1 = 0;
      var called2 = 0;
      var called3 = 0;
      var callback1 = function() {
        called1++;
      };
      var callback2 = function() {
        called2++;
      };
      var callback3 = function() {
        called3++;
      };
      var h1 = Async.run(callback1);
      var h2 = Async.run(callback2); //eslint-disable-line no-unused-vars
      var h3 = Async.run(callback3);
      Async.cancel(h1);
      Async.cancel(h3);
      setTimeout(function() {
        assert.equal(called1, 0);
        assert.equal(called2, 1);
        assert.equal(called3, 0);
        done();
      });
    });

  });

  suite('wait async', function() {

    test('async runs', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      Async.run(callback, 50);
      setTimeout(function() {
        assert.equal(called, 1);
        done();
      }, 51);
    });

    test('multiple asyncs of same fn run', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      Async.run(callback, 50);
      Async.run(callback, 50);
      Async.run(callback, 200);
      setTimeout(function() {
        assert.equal(called, 2);
        done();
      }, 51);
    });

    test('multiple asyncs of different fns run', function(done) {
      var called1 = 0;
      var called2 = 0;
      var called3 = 0;
      var callback1 = function() {
        called1++;
      };
      var callback2 = function() {
        called2++;
      };
      var callback3 = function() {
        called3++;
      };
      Async.run(callback1, 50);
      Async.run(callback2, 50);
      Async.run(callback3, 200);
      setTimeout(function() {
        assert.equal(called1, 1);
        assert.equal(called2, 1);
        assert.equal(called3, 0);
        done();
      }, 51);
    });

  });

  suite('cancel wait async', function() {

    test('async cancels', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      var h = Async.run(callback, 50);
      Async.cancel(h);
      setTimeout(function() {
        assert.equal(called, 0);
        done();
      }, 51);
    });

    test('multiple asyncs of same fn cancel', function(done) {
      var called = 0;
      var callback = function() {
        called++;
      };
      var h = [];
      h.push(Async.run(callback, 50));
      h.push(Async.run(callback, 50));
      h.push(Async.run(callback, 200));
      Async.cancel(h.pop());
      Async.cancel(h.pop());
      Async.cancel(h.pop());
      setTimeout(function() {
        assert.equal(called, 0);
        done();
      }, 51);
    });

    test('multiple asyncs of different fns cancel', function(done) {
      var called1 = 0;
      var called2 = 0;
      var called3 = 0;
      var callback1 = function() {
        called1++;
      };
      var callback2 = function() {
        called2++;
      };
      var callback3 = function() {
        called3++;
      };
      var h1 = Async.run(callback1, 50);
      var h2 = Async.run(callback2, 50); //eslint-disable-line no-unused-vars
      var h3 = Async.run(callback3, 200);
      Async.cancel(h1);
      Async.cancel(h3);
      setTimeout(function() {
        assert.equal(called1, 0);
        assert.equal(called2, 1);
        assert.equal(called3, 0);
        done();
      }, 51);
    });

  });

</script>
</body>
</html>
